#include "DXGraphics.h"


DXGraphics::DXGraphics()
{
	center = D3DXVECTOR3(10.0f, 10.0f, 0) ;	// set to the exact center of the sprite
	numFrames = 0.0f ;
	timeElapsed = 0.0f ;
	mouseButtonDown = resetButtonDown = cureButtonDown = infectButtonDown = false ;
	timePerUpdate = 1.0f ;
	InfectionRate = 30 ;
	CureRate = 50 ;
}

DXGraphics::~DXGraphics( )
{
	// clean up DirectX and COM
	cleanD3D( ) ;
}

// this function initializes and prepares Direct3D for use
void DXGraphics::initD3D(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);    // create the Direct3D interface

	a_hWnd = hWnd ;

    D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information

    ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
    d3dpp.Windowed = TRUE;    // program windowed, not fullscreen
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
    d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D

    // create a device class using this information and the info from the d3dpp stuct
    d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

	D3DXCreateSprite(d3ddev, &d3dspt);    // create the Direct3D Sprite object

	world.CreateWorld( sp ) ;

	for( int i = 0; i < 400; i++ )
		for( int j = 0; j < 400; j++ )
			sp[i].FindAdjacent( sp[j] ) ;

	D3DXCreateTextureFromFileEx(d3ddev,    // the device pointer
                                L"Normal.png",    // the sprite name
                                D3DX_DEFAULT_NONPOW2,    // default width
                                D3DX_DEFAULT_NONPOW2,    // default height
                                D3DX_DEFAULT,    // no mip mapping
                                NULL,    // regular usage
                                D3DFMT_A8R8G8B8,    // 32-bit pixels with alpha
                                D3DPOOL_MANAGED,    // typical memory handling
                                D3DX_DEFAULT,    // no filtering
                                D3DX_DEFAULT,    // no mip filtering
                                D3DCOLOR_XRGB(255, 0, 255),    // the hot-pink color key
                                NULL,    // no image info struct
                                NULL,    // not using 256 colors
                                &sprites[NORMAL]);    // load to sprite

	D3DXCreateTextureFromFileEx(d3ddev,    // the device pointer
                                L"Infected.png",    // the sprite name
                                D3DX_DEFAULT_NONPOW2,    // default width
                                D3DX_DEFAULT_NONPOW2,    // default height
                                D3DX_DEFAULT,    // no mip mapping
                                NULL,    // regular usage
                                D3DFMT_A8R8G8B8,    // 32-bit pixels with alpha
                                D3DPOOL_MANAGED,    // typical memory handling
                                D3DX_DEFAULT,    // no filtering
                                D3DX_DEFAULT,    // no mip filtering
                                D3DCOLOR_XRGB(255, 0, 255),    // the hot-pink color key
                                NULL,    // no image info struct
                                NULL,    // not using 256 colors
                                &sprites[INFECTED]);    // load to sprite

	D3DXCreateTextureFromFileEx(d3ddev,    // the device pointer
                                L"Carrier.png",    // the sprite name
                                D3DX_DEFAULT_NONPOW2,    // default width
                                D3DX_DEFAULT_NONPOW2,    // default height
                                D3DX_DEFAULT,    // no mip mapping
                                NULL,    // regular usage
                                D3DFMT_A8R8G8B8,    // 32-bit pixels with alpha
                                D3DPOOL_MANAGED,    // typical memory handling
                                D3DX_DEFAULT,    // no filtering
                                D3DX_DEFAULT,    // no mip filtering
                                D3DCOLOR_XRGB(255, 0, 255),    // the hot-pink color key
                                NULL,    // no image info struct
                                NULL,    // not using 256 colors
                                &sprites[CARRIER]);    // load to sprite

	D3DXCreateFont(d3ddev,    // the D3D Device
                   20,    // font height of 30
                   0,    // default font width
                   FW_NORMAL,    // font weight
                   1,    // not using MipLevels
                   true,    // italic font
                   DEFAULT_CHARSET,    // default character set
                   OUT_DEFAULT_PRECIS,    // default OutputPrecision,
                   DEFAULT_QUALITY,    // default Quality
                   DEFAULT_PITCH | FF_DONTCARE,    // default pitch and family
                   L"Arial",    // use Facename Arial
                   &d3dfnt);    // the font object

	return ;
}

void DXGraphics::Update( float dt )
{
	//Updates game cursor's position
	GetCursorPos(&mousePos) ; //gets window cursor position on monitor screen
	ScreenToClient( a_hWnd, &mousePos ) ; //maps the location of the cursor onto the client window

	//get mouse coordinates
	LONG mousePosX = mousePos.x ;
	LONG mousePosY = mousePos.y ;

	//update time and numFrames
	numFrames += 1.0f ;
	timeElapsed += dt ;

	//get DirectInput states
	gDInput->poll( ) ;

	//-----------------------------DIRECT INPUT DATA------------------------------------------------------------------------

	//Left mouse button will turn any square selected into a carrier
	if( gDInput->mouseButtonDown(0) )
	{
		if( !mouseButtonDown )
		{
			mouseButtonDown = true ;
			
			for( int i = 0; i < 400; i++ )
				if( mousePosX <= sp[i].position.x + 10.0f && mousePosX >= sp[i].position.x - 10.0f && mousePosY <= sp[i].position.y + 10.0f && mousePosY >= sp[i].position.y - 10.0f )
					sp[i].TurnSprite( ) ;

		}
	}
	else if( mouseButtonDown )
		mouseButtonDown = false ;

	//reset the simulation
	if( gDInput->keyDown( DIK_R ) )
	{
		if( !resetButtonDown )
		{
			resetButtonDown = true ;

			for( int i = 0; i < 400; i++ ) //turn all sprites back to normal
				sp[i].ResetSprite( ) ;

			//reset infection/cure rates
			InfectionRate = 50 ;
			CureRate = 30 ;
		}
	}
	else if( resetButtonDown )
		resetButtonDown = false ;

	//increase simulation speed
	if( gDInput->keyDown( DIK_UP ) )
	{
		if( !speedButtonDown )
		{
			speedButtonDown = true ;
			if( timePerUpdate > 0.1f )
				timePerUpdate -= 0.1f ;
		}
	}
	else if( speedButtonDown && !gDInput->keyDown( DIK_DOWN ) )
		speedButtonDown = false ;

	//decrease simulation speed
	if( gDInput->keyDown( DIK_DOWN ) )
	{
		if( !speedButtonDown )
		{
			speedButtonDown = true ;

			if( timePerUpdate < 1.0f )
				timePerUpdate += 0.1f ;
		}
	}
	else if( speedButtonDown && !gDInput->keyDown( DIK_UP ) )
		speedButtonDown = false ;

	//increase infection rate
	if( gDInput->keyDown( DIK_Q ) )
	{
		if( !infectButtonDown )
		{
			infectButtonDown = true ;
			
			if( InfectionRate < 100 )
				InfectionRate += 1 ;
		}
	}
	else if( infectButtonDown && !gDInput->keyDown( DIK_A ) )
		infectButtonDown = false ;

	//decrease infection rate
	if( gDInput->keyDown( DIK_A ) )
	{
		if( !infectButtonDown )
		{
			infectButtonDown = true ;

			if( InfectionRate > 10 )
				InfectionRate -= 1 ;
		}
	}
	else if( infectButtonDown && !gDInput->keyDown( DIK_Q ) )
		infectButtonDown = false ;

	//increase cure rate
	if( gDInput->keyDown( DIK_W ) )
	{
		if( !cureButtonDown )
		{
			cureButtonDown = true ;
			
			if( CureRate < 100 )
				CureRate += 1 ;
		}
	}
	else if( cureButtonDown && !gDInput->keyDown( DIK_S ) )
		infectButtonDown = false ;

	//decrease cure rate
	if( gDInput->keyDown( DIK_S ) )
	{
		if( !cureButtonDown )
		{
			cureButtonDown = true ;

			if( CureRate > 10 )
				CureRate -= 1 ;
		}
	}
	else if( cureButtonDown && !gDInput->keyDown( DIK_W ) )
		cureButtonDown = false ;

	//show current infection and cure rates
	sprintf_s( rules, "Infection Rate: %d\nCure Rate: %d\nTimePerFrame: %.1f", InfectionRate, CureRate, timePerUpdate ) ;

	//update simulation
	if( timeElapsed >= timePerUpdate )
	{
		//reset population count to 0
		numNormal = 0 ;
		numInfected = 0 ;

		//spread infection
		for( int i = 0; i < 400; i++ )
		{
			if( sp[i].checkTag( ) != NORMAL && !sp[i].isNewlyInfected( ) ) 
			{
				sp[i].InfectionCheck( sp[i].sprAdj->left, InfectionRate ) ;
				sp[i].InfectionCheck( sp[i].sprAdj->right, InfectionRate ) ;
				sp[i].InfectionCheck( sp[i].sprAdj->top, InfectionRate ) ;
				sp[i].InfectionCheck( sp[i].sprAdj->bottom, InfectionRate ) ;
			}
		}

		//cure infection and make headcount of normal/infected squares
		for( int i = 0; i < 400; i++ )
		{
			//cure infected if able
			if( sp[i].checkTag( ) == INFECTED && !sp[i].isNewlyInfected( ) ) 
				sp[i].CureCheck( CureRate ) ;

			//count square in total
			if( sp[i].checkTag( ) != NORMAL )
				numInfected++ ;
			else
				numNormal++ ;

			if( sp[i].checkTag( ) == INFECTED )
				sp[i].updateInfected( ) ;
		}

		//update population and time per frame
		sprintf_s( population, "Normal: %i\nInfected: %i", numNormal, numInfected ) ;

		timeElapsed = 0.0f; //reset timer
		numFrames = 0.0f ; //reset number of frames
	}
}


// this is the function used to render a single frame
void DXGraphics::render_frame( )
{
	D3DXMatrixIdentity( &matTransform ) ;

    // clear the window to a deep blue
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    d3ddev->BeginScene();    // begins the 3D scene

    d3dspt->Begin(D3DXSPRITE_ALPHABLEND);    // begin sprite drawing with transparent background

	for( int i = 0; i < 400; i++ )
	{
		D3DXMatrixTranslation( &spriteTranslation, sp[i].position.x, sp[i].position.y, 0 );	// move sprite from center
		d3dspt->SetTransform( &spriteTranslation ) ;
		d3dspt->Draw( sprites[sp[i].checkTag( )], NULL, &center, NULL, D3DCOLOR_XRGB( 255, 255, 255 ) );	// draw the sprite
	}

	// create a RECT to contain the text
    RECT textbox;	// declare textbox variable
	GetWindowRect(a_hWnd, &textbox);
	textbox.right = textbox.right - textbox.left;
	textbox.bottom = textbox.bottom - textbox.top - 40;
	textbox.left = 0;
	textbox.top = 0;

	d3dfnt->DrawTextA(NULL, "CONTROLS:\nClick on any square to change it to carrier\nR - reset simulation\nUp/Down Arrow - Increase/Decrease update speed\nQ/A - Change Infection Rate\nW/S - Change Cure Rate", -1, &textbox, DT_TOP | DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0));
	d3dfnt->DrawTextA(NULL, population, -1, &textbox, DT_TOP | DT_CENTER | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0));
	d3dfnt->DrawTextA(NULL, "RULES:\nCarriers always infect adjacent squares\nInfected squares can infect adjacent squares based on Infection Rate\nInfected squares can cure themselves based on Cure Rate\nCarriers can NEVER be cured", -1, &textbox, DT_BOTTOM | DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0));
	d3dfnt->DrawTextA(NULL, rules, -1, &textbox, DT_VCENTER | DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0));

	
    d3dspt->End();    // end sprite drawing

    d3ddev->EndScene();    // ends the 3D scene

    d3ddev->Present(NULL, NULL, NULL, NULL);   // displays the created frame on the screen
}


// cleans up Direct3D and COM
void DXGraphics::cleanD3D(void)
{
	for( int i = 0; i < 3; i++ )
		sprites[i]->Release();
	d3dfnt->Release() ;
    d3ddev->Release();
    d3d->Release();

    return;
}